#pragma once

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include "err.hpp"

namespace ns_server
{
    static const uint16_t defaultport = 8081;
    static const int backlog = 32;

    using func_t = std::function<std::string(const std::string &)>;

    class Tcpserver;
    class ThreadData
    {
    public:
        ThreadData(int fd, const std::string& ip, const uint16_t& port, Tcpserver* ts)
            :sock(fd), clientip(ip), clientport(port), current(ts)
        {}

    public:
        int sock;
        std::string clientip;
        uint16_t clientport;
        Tcpserver* current;
    };

    class Tcpserver
    {
    public:
        Tcpserver(func_t func, uint16_t port = defaultport)
            : func_(func), port_(port), quit_(true)
        {
        }

        void initserver()
        {
            listensock_ = socket(AF_INET, SOCK_STREAM, 0);
            if (listensock_ < 0)
            {
                std::cerr << "创建套接字错误" << std::endl;
                exit(SOCKET_ERR);
            }

            // 2.bind
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(port_);
            local.sin_addr.s_addr = INADDR_ANY;
            if (bind(listensock_, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                std::cerr << "绑定套接字错误" << std::endl;
                exit(BIND_ERR);
            }

            // 3.监听
            if (listen(listensock_, backlog) < 0)
            {
                std::cerr << "监听套接字错误" << std::endl;
                exit(LISTEN_ERR);
            }
        }

        void start()
        {
            quit_ = false;
            while (!quit_)
            {
                // 1.接收连接
                struct sockaddr_in client;
                socklen_t len = sizeof(client);
                int sock = accept(listensock_, (struct sockaddr *)&client, &len);
                if (sock < 0)
                {
                    std::cerr << "accept 错误" << std::endl;
                    continue;
                }

                std::string clientip = inet_ntoa(client.sin_addr);
                uint16_t clientport = ntohs(client.sin_port);

                std::cout << "获取新连接成功：" << sock << " from " << listensock_ << ", 客户端IP-端口号：" << clientip << "-" << clientport << std::endl;
                //service(sock, clientip, clientport);
                pthread_t tid;
                ThreadData *td = new ThreadData(sock, clientip, clientport, this);
                pthread_create(&tid, nullptr, threadRoutine, td);
            }
        }

        static void* threadRoutine(void* args)
        {
            pthread_detach(pthread_self());
            ThreadData* td = static_cast<ThreadData*>(args);
            td->current->service(td->sock, td->clientip, td->clientport);
            delete td;
            return nullptr;
        }

        // 处理从客户端读取到的数据并返回
        void service(int sock, const std::string& clientip, const uint16_t& clientport)
        {
            std::string who = clientip + "-" + std::to_string(clientport);
            char buffer[1024];
            while (true)
            {
                // 从套接字文件描述符读取数据
                ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
                if (s > 0) // 读取成功
                {
                    buffer[s] = 0;
                    std::string res = func_(buffer); // 回调函数处理数据
                    std::cout << who << ">>> " << res << std::endl;

                    // 将处理后的数据返回套接字对应的客户端
                    write(sock, res.c_str(), res.size());
                }
                else if (s == 0) // 对方连接关闭
                {
                    close(sock);
                    std::cout << "客户端" << who <<"退出，服务器端也退出" << std::endl;
                    break;
                }
                else
                {
                    close(sock);
                    std::cerr << "读取客户端数据错误:" << strerror(errno) << std::endl;
                    break;
                }
            }
        }

        ~Tcpserver()
        {
        }

    private:
        uint16_t port_;
        int listensock_;
        bool quit_;
        func_t func_;
    };
}